package net.quanter.ddns4java;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.List;

import net.quanter.ddns4java.enums.ProviderEnum;
import net.quanter.ddns4java.enums.RecordType;
import net.quanter.ddns4java.network.Member3322;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.BeanUtilsBean2;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Java版本DDNS启动类
 *
 * @author harley-dog
 */
public class Ddns4JavaStarter {
    static Logger logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
    static BeanUtilsBean beanUtils = BeanUtilsBean2.getInstance();
    static NetworkProxy networkProxy = new Member3322();

    /**
     * 一：读取配置文件，如果找不到退出
     * 二：解析xml,判断必须存在的配置项,不存在则退出
     * 二：读取本机ip，读不到就退出
     * 三：
     *
     * @param args
     * @throws FileNotFoundException
     */
    public static void main(String[] args) {

        InputStream in = getInput(args);
        if (in == null) {
            return;
        }
        DdnsConfig ddnsConfig = null;
        try {
            ddnsConfig = parseXml(in);
        } catch (Exception e) {
            logger.error("解析xml配置文件出错");
            return;
        }
        if (ddnsConfig == null || ddnsConfig.providerList.isEmpty() || ddnsConfig.domainList.isEmpty()) {
            return;
        }
        DdnsConfig finalDdnsConfig = ddnsConfig;

        String ip = networkProxy.getPublicIp();
        if(ip==null){
            logger.error("获取不到本机的公网ip");
            return;
        }
        ddnsConfig.providerList.stream()
            .filter(provider -> provider.init())
            .forEach(provider -> process(provider, finalDdnsConfig.domainList, ip));

    }

    /**
     * 从classes或者指定文件地址下读取文件
     *
     * @param args
     * @return
     */
    public static InputStream getInput(String[] args) {
        InputStream in = null;
        if (args.length == 0) {
            try {
                in = Ddns4JavaStarter.class.getClassLoader().getResourceAsStream("ddns.xml");
            } catch (Exception e) {
                logger.error("找不到文件{}，程序退出", "classes/ddns-sample.xml");

            }
        } else {
            String filename = args[0];
            try {
                in = new BufferedInputStream(new FileInputStream(filename));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
        return in;
    }

    public static DdnsConfig parseXml(InputStream in) throws Exception {
        DdnsConfig ddnsConfig = new DdnsConfig();
        SAXReader reader = new SAXReader();
        Document document;
        try {
            document = reader.read(in);
        } catch (DocumentException e) {
            logger.error("解析配置文件出错，程序退出:", e);
            return null;
        }
        Element root = document.getRootElement();
        Element eleProviders = root.element("providers");
        List<Element> providerEles = eleProviders.elements("provider");
        for (Element eleProvider : providerEles) {
            String provalue = eleProvider.attributeValue("value");
            ProviderEnum providerEnum = null;
            try {
                providerEnum = ProviderEnum.valueOf(provalue);
            } catch (IllegalArgumentException e) {
                logger.error("解析配置文件provider出错");
                continue;
            }
            List<Element> eleProviderEleList = eleProvider.elements();
            for (Element elepro : eleProviderEleList) {
                String name = elepro.getName();
                String value = elepro.getStringValue();
                beanUtils.setProperty(providerEnum.provider, name, value);
            }
            ddnsConfig.providerList.add(providerEnum.provider);
        }

        Element eleDomains = root.element("domains");
        List<Element> domainList = eleDomains.elements("domain");
        for (Element domainEle : domainList) {
            String proName = domainEle.attributeValue("name");
            Domain domain = new Domain();
            domain.setName(proName);
            Element prefixsEle = domainEle.element("prefixs");
            List<Element> elementList = prefixsEle.elements("prefix");
            elementList.forEach(elePrefix -> domain.addPrefix(elePrefix.getStringValue()));
            ddnsConfig.getDomainList().add(domain);
        }
        return ddnsConfig;
    }

    /**
     * provider单个处理域名
     *
     * @param provider   处理者
     * @param domainList 域名列表
     */
    private static void process(Provider provider, List<Domain> domainList, String ip) {
        domainList.stream().filter(domain -> domain.valid()).forEach(domain -> process(provider, domain, ip));
    }

    /**
     * provider单个处理域名
     *
     * @param provider 处理者
     * @param domain   单个域名
     */
    private static void process(Provider provider, Domain domain, String ip) {
        boolean hasDomain = provider.hasDomain(domain.getName());
        if (!hasDomain) {
            return;
        }
        List<DomainRecord> domainRecordList = provider.findRecordsByDomain(domain.getName());

        for(String prefix:domain.getPrefixs()){
            boolean isFind = false;
            for(DomainRecord record:domainRecordList){
                if(prefix.equalsIgnoreCase(record.prefix)){
                    //说明找到了
                    isFind = true;
                    //再比较是否相同
                    if(record.getType()!= RecordType.A || !ip.equalsIgnoreCase(record.value)){
                        DomainRecord updateRecord = new DomainRecord(record.getId(),record.getDomain(),record.getPrefix(),ip,RecordType.A.name());
                        boolean b = provider.updateRecord(updateRecord);
                        if(b){
                            logger.info("修改{}的A解析记录由[{}]，变为[{}]",record.prefix+"."+record.domain,record.value,updateRecord.value);
                        }else {
                            logger.error("修改{}的A解析记录由[{}]，变为[{}]-失败");
                        }
                    }
                    break;
                }
            }
            if(!isFind){
                //如果没找到，就要新增一个
                DomainRecord insertRecord = new DomainRecord(null,domain.getName(),prefix,ip,RecordType.A.name());
                boolean b = provider.insertRecord(insertRecord);
                if(b){
                    logger.info("新增{}的A解析记录由[{}]",prefix+"."+domain.getName(),insertRecord.value);
                }
            }
        }
    }

}
